package main

import (
	"math"
)

// 滑动窗口，双指针遍历
func getMinPassword(s string) int {
	// 结果长度定义为最大值
	rst := math.MaxInt32
	// map 记录窗口内元素及个数
	charMap := make(map[byte]int, 0)
	// 记录三个特殊字符, 使用map当做集合(比使用集合，直接枚举也行，只有三种特殊字符)
	speMap := map[byte]struct{}{'@': {}, '$': {}, '%': {}}
	// 记录无重复字母的数量
	letNum := 0
	// 记录特殊字符数
	speNum := 0
	for i, j := 0, 0; j < len(s); j++ {
		// 1. 窗口内该字符数加1, 判断是否是新字符
		if _, ok := charMap[s[j]]; !ok {
			// 如果是特殊字符，加 1
			if _, ok := speMap[s[j]]; ok {
				speNum += 1
			} else {
				letNum += 1
			}
		}
		charMap[s[j]] += 1
		// 如果满足条件，缩 i，找到最小的,  1 2 3 4 5
		// 此时退出循环已经是 不满足了， 计算长度为 j - i + 2
		for letNum >= 5 && speNum >= 1 {
			// 放到这里，每次 i++, 都要判断一次结果了~！
			if j-i+1 < rst {
				rst = j - i + 1
			}
			charMap[s[i]] -= 1
			// 如果当前窗口内该词数量降为0了， 那么就减少一个相应
			if charMap[s[i]] == 0 {
				if _, ok := speMap[s[j]]; ok {
					speNum -= 1
				} else {
					letNum -= 1
				}
			}
			i++
		}
	}
	// 如果没有满足的，那返回的就是 默认值
	return rst
}

//func main() {
//	//s := "i@love@track"
//	//rst := getMinPassword(s)
//	//fmt.Println(rst)
//	//votedMap := make(map[int][]int, 0)
//	//a := votedMap[1] = make()
//	//a[0] += 1
//	//fmt.Println(a)
//	//fmt.Println(votedMap[1])
//}
